﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using AGDN;

namespace Sudum
{
    class StarsEffect
    {
       
        public void Draw()
        {
            // draw the star lines
            basicEffect.VertexColorEnabled = true;
            
            basicEffect.World = Matrix.Identity;
            basicEffect.Projection = camera.GetProjection();
            basicEffect.View = camera.GetView();

            basicEffect.Begin();
            basicEffect.CurrentTechnique.Passes[0].Begin();

            Sudum.Me.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>
                (PrimitiveType.LineList, pointList, 0, m_stars.Count);

            basicEffect.CurrentTechnique.Passes[0].End();
            basicEffect.End();
        }

        public void Update()
        {
            Vector3 tail = dir * kStarInitialLength;

            Vector3 p1;
            Vector3 p2;       

            for (int i = 0, j = 1; i < kStarsDensity; i += 2, j += 2)
            {
                // move the star
                m_stars[i] -= dir * kStarSpeed;

                // the tail move with him
                p1 = m_stars[i] + tail * 0.1f;
                p2 = m_stars[i] + tail;

                // move this star to the far front of the camera if it passed it
                float dc = Vector3.Dot((m_stars[i] - camera.EyePos), dir);
                if (dc < 0)
                {                    
                    m_stars[i] += dir * (float)rand.NextDouble() * kStarMaxDepth;
                }

                // save the new star tail
                pointList[i].Position = p1;
                pointList[j].Position = p2;
            }    
        }

        void GenerateStars()
        {            
            //Generate a cloud of stars around camera's position,dir            
            for (int i = 0; i < kStarsDensity; ++i)
            {
                m_stars.Add(GeneratePosition());
            }

            //
            // generate lines from the stars with random tail kStarInitialLength (faking the tail)
            //

            //dir = (m_camera.Target - m_camera.EyePos);
            //dir.Normalize();
            dir = Vector3.UnitZ;

            Vector3 tail = dir * kStarInitialLength;

            pointList = new VertexPositionColor[m_stars.Count * 2];

            Vector3 p1;
            Vector3 p2;

            Color c1 = Color.White;
            c1.A = 128;
            Color c2 = Color.Gray;
            c2.A = 128;
            for (int i = 0, j = 1; i < kStarsDensity; i += 2, j += 2)
            {
                p1 = m_stars[i] + tail * 0.1f;
                p2 = m_stars[i] + tail;

                pointList[i] = new VertexPositionColor(p1, c1);
                pointList[j] = new VertexPositionColor(p2, c2);
            }            
        }

        

        Vector3 GeneratePosition()
        {            
            // generate the stars positions around the camera randomly and with some random depth

            float randRadius = kStarsDistributionRadius + (float)rand.NextDouble() * 10.0f;

            // the star is on the left or the right?
            int sign = rand.Next(1, 9);
            if (sign > 3)
                randDir.X = 5.0f * (float)rand.NextDouble() * randRadius;
            else
                randDir.X = -5.0f * (float)rand.NextDouble() * randRadius;

            // the star is on the top or the bottom?
            sign = rand.Next(1, 9);
            if(sign > 3)
                randDir.Y = 5.0f * (float)rand.NextDouble() * randRadius;
            else
                randDir.Y = -5.0f * (float)rand.NextDouble() * randRadius;
            
            // add some depth
            randDir.Z = (float)rand.NextDouble() * kStarMaxDepth;
            
            // to see the stars as lines, uncomment the following line
            //m_randDir.Normalize();

            //tmpPosition = camera.EyePos + randDir;
            Vector3 spawnPoint = new Vector3(0, 0, 100);
            tmpPosition = spawnPoint + randDir;

            return tmpPosition;
        }

        public StarsEffect(Camera cam)
        {                        
            m_stars = new List<Vector3>();
            rand = new Random();
            camera = cam;

            GenerateStars();
        }

        BasicEffect basicEffect = new BasicEffect(Sudum.Me.GraphicsDevice, null);
        VertexPositionColor[] pointList = null;

        Random rand = null;
        Vector3 tmpPosition;
        Vector3 randDir;
        Vector3 dir;
        

        List<Vector3> m_stars;        

        Camera camera;
        
        const float kStarsDistributionRadius = 20.0f;
        const int kStarsDensity = 500;
        const float kStarInitialLength = 2;
        const float kStarMaxDepth = 100;

        const float kStarSpeed = 0.016f * 80.0f;
    }
}
